home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / GRAPHICS / RAYTRACE.ZIP / LOADPCX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-27  |  9.8 KB  |  309 lines

  1. #include "loadpcx.h"
  2. #include <stdio.h>  /* for FILE functions */
  3. #include <mem.h>    /* for memcpy,memset */
  4. #include <malloc.h>  /* for farmalloc,farfree */
  5.  
  6. /*  Simple macros used to dynamically allocate/free memory */
  7. /*  NOTE that they are only used to allocate a file buffer */
  8. /*  all other allocations are explicit far allocations     */
  9.  
  10. #define CREATE_BLOCK(size) malloc(size)
  11. #define FREE_BLOCK(ptr) free(ptr)
  12.  
  13. /*      Header of a PCX file    */
  14.  
  15.     int     ErrorCode;
  16.  
  17.  
  18. struct PcxHeader
  19. {
  20.         byte manufacturer; /* 0x0a --signifies a PCX file */
  21.  
  22.         byte version;      /* version 5 is what we look for */
  23.  
  24.         byte encoding;     /* when 1,it's RLE encoding (only type as of yet) */
  25.  
  26.         byte bitsperpixel; /* how many bits to represent 1 pixel */
  27.  
  28.         word xmin, ymin, xmax, ymax; /* dimensions of window */
  29.  
  30.         word HDPI, VDPI;   /* device resolution (horizontal,vertical) */
  31.  
  32.         struct VgaPalette colormap[16]; /* 16-color palette */
  33.  
  34.         byte reserved;
  35.  
  36.         byte nplanes;      /* number of color planes */
  37.  
  38.         word bytesperline; /* number of bytes per line (per color plane) */
  39.  
  40.         word palette_info; /* 1 = color,2 = grayscale (unused in v.5+) */
  41.  
  42.         word swidth,sheight; /* width and height of screen */
  43.  
  44.         byte filler[54];   /* used to fill-out 128 byte header (useless) */
  45. };
  46.  
  47. /*      We keep a static copy of PcxHeader to work with */
  48.  
  49. static struct PcxHeader head;
  50.  
  51. /*------------------------------------------------------------------------*/
  52. /*                                                                        */
  53. /*  pcx_decode_line(FILE *,byte *bufp,word bpline);                  */
  54. /*                                                                        */
  55. /*  This function modified from:                                          */
  56. /*                                                                        */
  57. /*  'The C Users Journal' magazine, August 1991 issue                     */
  58. /*   Article 'PCX Graphics' by Ian Ashdown                                */
  59. /*                                                                        */
  60. /*  Decode one line of EGA or VGA PCX file.                               */
  61. /*  Returns FALSE only if a file error was encountered.                   */
  62. /*                                                                        */
  63. /*------------------------------------------------------------------------*/
  64.  
  65. static bool near pcx_decode_line(FILE * fp,byte *bufp,word bpline)
  66. {
  67.         int data;   /* data byte retrieved from file */
  68.         int count;  /* repeat count */
  69.         int offset; /* buffer offset */
  70.  
  71.         offset = 0;
  72.  
  73.         while (offset < bpline)
  74.         {
  75.         /*      Important to check for EOF here, so that we do not overrun */
  76.         /*      buffer (if not checked, it will judge EOF to be a 63 repeat count */
  77.  
  78.                 if ((data = getc(fp)) == EOF)
  79.                         return FALSE;
  80.  
  81.         /*      If upper 2 bits are set, it's a count byte */
  82.  
  83.                 if ((data & 0xc0) == 0xc0)
  84.                 {
  85.                         count = data & 0x3f;    /* mask off repeat count */
  86.  
  87.                         if ((data = getc(fp)) == EOF)   /* get data to repeat */
  88.                                 return FALSE;
  89.  
  90.                         _fmemset(bufp,data,count);      /* duplicate byte */
  91.                         bufp += count;
  92.                         offset += count;
  93.                 }
  94.                 else
  95.                 {
  96.                         *bufp++ = (byte) data;
  97.                         offset++;
  98.                 }
  99.         }
  100.         return TRUE;
  101. }
  102.  
  103. /*------------------------------------------------------------------------*/
  104. /*                                                                        */
  105. /*  valid_pcx(FILE * fp);                                                 */
  106. /*                                                                        */
  107. /*  Check the header and the file to see if it's a valid 256-color file   */
  108. /*  struct PcxHeader 'head' must be set prior to calling this function.   */
  109. /*                                                                        */
  110. /*------------------------------------------------------------------------*/
  111.  
  112. bool valid_pcx(FILE * fp)
  113. {
  114.         long curpos;
  115.         int palsig;
  116.  
  117. /*      If not a PCX file, or unknown type, return invalid */
  118.  
  119.         if (head.manufacturer != 0x0a || head.version != 5 ||
  120.                 head.encoding != 1)
  121.             {
  122.             ErrorCode = 4;
  123.                         return FALSE;
  124.             }
  125.  
  126. /*      If it's not a 256-color PCX file, return invalid */
  127.  
  128.         if (head.nplanes != 1 || head.bitsperpixel != 8)
  129.             {
  130.             ErrorCode = 1;
  131.                 return FALSE;
  132.             }
  133. /*
  134. *       Read the 769th byte from the end of the file to see if it contains
  135. *       the 'palette signature', being sure to restore file position after
  136. */
  137.         curpos = ftell(fp);
  138.  
  139.         fseek(fp,-769,SEEK_END);
  140.  
  141.         palsig = fgetc(fp);
  142.  
  143.         fseek(fp,curpos,SEEK_SET);
  144.  
  145.         if (palsig != 0xc)  /* palette signature? */
  146.             {
  147.             ErrorCode = 2;
  148.                 return FALSE;   /* nope, bad PCX file */
  149.             }
  150.  
  151.         return TRUE;
  152. }
  153.  
  154.  
  155. /*------------------------------------------------------------------------*/
  156. /*                                                                        */
  157. /*  int load_pcx(char * name,PcxPix * pix,VgaPalette * pal);              */
  158. /*                                                                        */
  159. /*  Decode a pcx file, place the image (and size info) into 'pix',        */
  160. /*  and place the 256-color palette into 'pal'                            */
  161. /*                                                                        */
  162. /*  NOTE: Rarely, a PCX file is saved with extra padding appended to      */
  163. /*  each scan line. When it is done, it's only to make each scan line     */
  164. /*  have an even number of bytes. This function (and most others) just    */
  165. /*  loads these 'pad' bytes as part of the image. In most (if not all)    */
  166. /*  cases, a PCX file is saved as a whole video page (in which no padding */
  167. /*  would be needed), so this isn't much of a concern.                    */
  168. /*------------------------------------------------------------------------*/
  169.  
  170. int load_pcx(const char *name,struct PcxPix *pix,struct VgaPalette *pal)
  171. {
  172.         FILE * fp;     /*  FILE, and  */
  173.         char * fbuf;   /* it's buffer */
  174.  
  175.         word width,height,theight;
  176.         long    piclen;
  177.         byte *pcx_image;
  178.         byte *dest;
  179.         byte *tpal;
  180.  
  181. /*      Open the file in read-only binary mode */
  182.  
  183.         fp = fopen(name,"rb");
  184.         if (fp == NULL)
  185.             {
  186.             ErrorCode = -1;
  187.                 return pcx_openerr;
  188.             }
  189.  
  190. /*      Read in the header */
  191.  
  192.         if (fread(&head,sizeof(struct PcxHeader),1,fp) != 1)
  193.         {
  194.             ErrorCode = -2;
  195.                 fclose(fp);
  196.                 return pcx_ferror;
  197.         }
  198.  
  199. /*      Ensure that the pcx file is valid */
  200.  
  201.         if (!valid_pcx(fp))
  202.         {
  203.                 fclose(fp);
  204.                 return pcx_invalid;
  205.         }
  206. /*      Calculate the width and height of image (see notes above on width) */
  207. /*      Bytes-per-line is used, since it includes padding count */
  208.  
  209.         width = head.bytesperline;
  210.         height = head.ymax - head.ymin + 1;
  211.  
  212.         piclen = width * height;
  213.         if (piclen > 64000L)
  214.             {
  215.             fclose(fp);
  216.             ErrorCode = -5;
  217.             return(pcx_invalid);
  218.             }
  219.  
  220. /*      Now allocate space to save the image in */
  221.  
  222.         pcx_image = malloc(piclen);
  223.  
  224. /*      Allocate a buffer for use with the FILE structure */
  225.  
  226.         fbuf = CREATE_BLOCK(BUFSIZ);
  227.  
  228. /*      If any allocations failed, return with an out-of-memory error */
  229.  
  230.         if (fbuf == NULL || pcx_image == NULL)
  231.         {
  232.             if (fbuf == NULL)
  233.                 printf("fbuf failed\n");
  234.  
  235.             if (pcx_image == NULL)
  236.                 {
  237.                 printf("pcx_image failed\n");
  238.                 printf("WT:%d HT:%d\n",width,height);
  239.                 }
  240.                 ErrorCode = -4;
  241.                 fclose(fp);
  242.  
  243.   /* If any allocations _did_ work, be sure to free them up before leaving */
  244.                 if (fbuf != NULL)
  245.                         FREE_BLOCK(fbuf);
  246.                 if (pcx_image != NULL)
  247.                         free(pcx_image);
  248.  
  249.                 return pcx_nomem;
  250.         }
  251.  
  252.         setbuf(fp,fbuf);
  253.  
  254. /*      Going row by row, read the data from the file */
  255.  
  256.         dest = pcx_image;
  257.         theight = height;
  258.  
  259.         while (theight--)
  260.         {
  261.                 if (!pcx_decode_line(fp,dest,head.bytesperline))
  262.                         goto file_error;
  263.  
  264.                 dest += width;
  265.         }
  266.  
  267. /*      Now read in the palette */
  268.  
  269.         fseek(fp,-768,SEEK_END);
  270.  
  271.         fread(pal,sizeof(struct VgaPalette),256,fp);
  272.  
  273. /*      If an error occured, cleanup all buffers and return with an error */
  274.  
  275.         if (ferror(fp))
  276.         {
  277. file_error:
  278.                 ErrorCode = -5;
  279.                 fclose(fp);
  280.                 FREE_BLOCK(fbuf);
  281.                 free(pcx_image);
  282.                 return pcx_ferror;
  283.         }
  284.  
  285. /*      Free up routine buffers, and setup pix's data   */
  286.  
  287.         fclose(fp);
  288.         FREE_BLOCK(fbuf);
  289.  
  290.         pix->image = pcx_image;
  291.         pix->width = width;
  292.         pix->height = height;
  293.  
  294. /*      Last but not least, set the palette to the VGA's format */
  295. /*      It's accomplished by simply shifting each RGB byte to the right twice */
  296.  
  297.         theight = 768;
  298.         tpal = (byte *)pal;
  299.  
  300.         while (theight--)
  301.                 *tpal++ >>= 2;
  302.  
  303. /*  Everythings A-OK! */
  304.  
  305.         return pcx_ok;
  306. }
  307.  
  308.  
  309.